using System;
using System.Runtime.InteropServices;
using System.Text.Json.Serialization;
using bitzhuwei.Compiler;

namespace bitzhuwei.JsonFormat {
    /// <summary>
    /// Correspond to the Vn node Value in the grammar(Json).
    /// </summary>
    public partial class JsonValue {
        // [12] Value = 'null' ;
        // [13] Value = 'true' ;
        // [14] Value = 'false' ;
        // [15] Value = 'number' ;
        // [16] Value = 'string' ;
        // [17] Value = Object ;
        // [18] Value = Array ;

        public enum Kind { Null, True, False, Number, String, Object, Array }
        public readonly Kind kind;

        [StructLayout(LayoutKind.Explicit)]
        public struct Union {
            /// <summary>
            /// number or string
            /// </summary>
            [FieldOffset(0)]
            public string value;
            [FieldOffset(0)]
            public List<JsonMember> @Object;
            [FieldOffset(0)]
            public List<JsonValue> @Array;
        }
        public readonly Union union;

        // [12] Value = 'null' ;
        // [13] Value = 'true' ;
        // [14] Value = 'false' ;
        // [15] Value = 'number' ;
        // [16] Value = 'string' ;
        public JsonValue(Kind kind, string value) {
            this.kind = kind;
            this.union.value = value;
        }

        // [17] Value = Object ;
        public JsonValue(List<JsonMember> r0) {
            this.kind = Kind.Object;
            this.union.Object = r0;
        }

        // [18] Value = Array ;
        public JsonValue(List<JsonValue> r0) {
            this.kind = Kind.Array;
            this.union.Array = r0;
        }

        public override string ToString() {
            string result = "";
            switch (this.kind) {
            case Kind.Null: result = this.union.value; break;
            case Kind.True: result = this.union.value; break;
            case Kind.False: result = this.union.value; break;
            case Kind.Number: result = this.union.value; break;
            case Kind.String: result = this.union.value; break;
            case Kind.Object: result = $"{{ {this.union.Object.Count} pairs }}"; break;
            case Kind.Array: result = $"{{ {this.union.Array.Count} values }}"; break;
            default: throw new NotImplementedException();
            }
            return result;
        }
    }
}
